package nbcp.myoql.db

import com.zaxxer.hikari.HikariDataSource
import nbcp.base.comm.*
import nbcp.base.extend.*
import nbcp.base.utils.*
import nbcp.myoql.db.comm.*
import nbcp.myoql.db.enums.*
import nbcp.myoql.db.sql.DataSourceScope
import nbcp.myoql.db.sql.SqlEntityCollector
import nbcp.myoql.db.sql.base.BaseAliasSqlSect
import nbcp.myoql.db.sql.base.SqlColumnName
import nbcp.myoql.db.sql.base.SqlParameterData
import nbcp.myoql.db.sql.component.RawQuerySqlClip
import nbcp.myoql.db.sql.component.RawUpdateSqlClip
import nbcp.myoql.db.sql.extend.getDbType
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
import org.springframework.util.StringUtils
import javax.sql.DataSource

/**
 * 请使用 db.sql
 */
object dbSql {

    //所有的组。
    @JvmStatic
    val groups = mutableSetOf<IDataGroup>()

//    var getSqlEntity: ((tableName: String) -> SqlBaseMetaTable<*>)? = null

    @JvmStatic
    val sqlEvents by lazy {
        return@lazy SpringUtil.getBeanWithNull(SqlEntityCollector::class.java);
    }

    @JvmStatic
    fun getCurrentScopeSqlDatabaseEnum(): SqlDatabaseEnum? {
        return db.sql.getScopeDataSource()!!.getDbType()
    }
//    @JvmStatic
//    val sqlDatabaseType: SqlDatabaseEnum?
//        get() {
//        if (SpringUtil.containsBean(DataSourceAutoConfiguration::class.java) == false) {
//            return@lazy null;
//        }
//
//        var conn = config.getConfig("spring.datasource.url").AsString();
//
//        if (conn.startsWith("jdbc:mysql://") || conn.startsWith("jdbc:mariadb://")) {
//            return@lazy SqlDatabaseEnum.MY_SQL
//        }
//
//        if (conn.startsWith("jdbc:sqlserver://")) {
//            return@lazy SqlDatabaseEnum.SQL_SERVER
//        }
//        if (conn.startsWith("jdbc:oracle:")) {
//            return@lazy SqlDatabaseEnum.ORACLE
//        }
//        if (conn.startsWith("jdbc:postgresql://")) {
//            return@lazy SqlDatabaseEnum.POSTGRESQL
//        }
//        return@lazy null;
//        }

    @JvmStatic
    fun getSqlQuoteName(value: String): String {
        var type = getCurrentScopeSqlDatabaseEnum();
        if (type == SqlDatabaseEnum.MY_SQL) {
            return "`${value}`"
        } else if (type == SqlDatabaseEnum.SQL_SERVER) {
            return "[${value}]"
        } else {
            return """"${value}""""
        }
    }

    @JvmStatic
    fun mergeSqlSects(vararg columns: BaseAliasSqlSect): SqlParameterData {
        var ret = SqlParameterData();

        ret.expression = columns.map {
            if (it is SqlColumnName) {
                return@map it.toSingleSqlData()
            } else if (it is SqlParameterData) {
                return@map it
            }
            throw RuntimeException("不识别的类型:${it::class.java.name}")
        }.map { it.expression }.joinToString(",")


        columns.forEach {
            if (it is SqlParameterData) {
                ret.values += it.values
            }
        }

        return ret;
    }

    private val dataSourceMap = mutableMapOf<String, DataSource>();

    @JvmStatic
    fun getDataSource(uri: String, username: String, password: String): DataSource? {
        var key = "${uri}-${username}-${password}"
        var dataSource = dataSourceMap.get(key);
        if (dataSource != null) {
            return dataSource;
        }

        var properties = SpringUtil.getBean<DataSourceProperties>();

        properties.url = uri;
        properties.username = username;
        properties.password = password;

        dataSource =
            properties.initializeDataSourceBuilder().type(HikariDataSource::class.java)
                .build() as HikariDataSource
        if (StringUtils.hasText(properties.name)) {
            dataSource.poolName = properties.name
        }

        dataSourceMap.put(key, dataSource);
        return dataSource
    }

    /**
     * 获取当前作用域的 DataSource，如果没有，获取默认的。
     */
    @JvmStatic
    fun getScopeDataSource(): DataSource? {
        return scopes.getLatest(DataSourceScope::class.java)?.value ?: SpringUtil.getBeanWithNull(
            DataSource::class
        ) ?: throw RuntimeException("找不到DataSource数据源")
    }

    @JvmStatic
    fun json_array(list: Collection<Any?>): SqlParameterData {
        return SqlParameterData(
            "json_array(${
                list.filter { it != null }.map { it.AsString().WrapWith("'") }.joinToString(",")
            })"
        )
    }


    /**
     * 动态执行sql
     */
    fun rawQuery(
        sqlWithVar: String,
        sqlValue: JsonMap = JsonMap(),
        tableName: String = ""
    ): RawQuerySqlClip {
        return RawQuerySqlClip(sqlWithVar, sqlValue, tableName)
    }


    /**
     * 动态执行sql
     * @param sqlWithVar 使用冒号+变量名的形式表示！ :变量名
     *
     */
    fun rawUpdate(
        sqlWithVar: String,
        sqlValue: JsonMap = JsonMap(),
        tableName: String = ""
    ): RawUpdateSqlClip {
        return RawUpdateSqlClip(sqlWithVar, sqlValue, tableName)
    }

    fun getLimitOffset(skip: Int, take: Int): String {
        var defTake = take;
        if (skip <= 0 && defTake < 0) {
            return "";
        }

        defTake = 99999;

        var type = getCurrentScopeSqlDatabaseEnum();

        if (skip > 0 && defTake >= 0) {
            if (type.IsIn(SqlDatabaseEnum.SQL_SERVER)) {
                return "offset ${skip} rows fetch next ${take} rows only"
            }
            if (type.IsIn(SqlDatabaseEnum.POSTGRESQL)) {
                return "offset ${skip}  limit ${take}"
            }

            return "limit ${skip},${take}"
        } else if (defTake >= 0) {
            if (type.IsIn(SqlDatabaseEnum.SQL_SERVER)) {
                return "fetch next ${take} rows only"
            }

            return "limit  ${take}"
        }
        return "";
    }

//    /**
//     * 根据表名，以及是不是读取操作，动态返回DataSource
//     */
//    var sqlDataSourceFunc: ((String, Boolean) -> DataSource)? = null


//    private var dynamicTableDataSource = StringKeyMap<DataSource>();
//
//    /**
//     * 指派集合到数据库
//     */
//    fun bindTableName2Database(tableName: String, data: DataSource) {
//        this.dynamicTableDataSource.set(tableName, data)
//    }
//
//    fun unbindTableName2Database(tableName: String) {
//        this.dynamicTableDataSource.remove(tableName)
//    }
//
//    /**
//     * 根据集合定义，获取 JdbcTemplate
//     */
//    fun getJdbcTemplateByTableName(tableName: String): JdbcTemplate? {
//        var dataSource = dynamicTableDataSource.get(tableName);
//        if (dataSource == null) return null;
//
//        return JdbcTemplate(dataSource, true)
//    }
}